home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 144 / Gekkan Dennou Club - 2000.5 Vol. 144 (Japan) (Track 1).bin / docs / asm / asm68k13.doc
Encoding:
Text File  |  2000-04-06  |  39.7 KB  |  1,246 lines

  1. ────────────────────────────────────
  2.         X680x0アセンブラ講座    #$13
  3.  
  4.           《アセンブラを使いこなすテクニック》
  5.  
  6.                 鎌田  誠
  7. ────────────────────────────────────
  8.  
  9.  今回は、アセンブラのプログラム書くときに使える小技をいろいろ紹介します。
  10.  
  11. これらのテクニックを使いこなして、効率のよいプログラミングを目指しましょ
  12.  
  13. う。
  14.  
  15.  
  16.  ここでは HAS060.X(最新版は月刊電脳倶楽部 140 号に収録)を使う場合につ
  17.  
  18. いて説明します。AS.X や HAS.X では使えない機能も含まれているので注意して
  19.  
  20. 下さい。また、例を挙げるだけで細かい文法の説明を省略しているところがあり
  21.  
  22. ます。是非、HAS060.X に添付されているマニュアルなども参照して下さい。
  23.  
  24.  
  25. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  26.  
  27.     注釈の書き方
  28.  
  29. ────────────────────────────────────
  30.  
  31.  プログラムの中に注釈を書くときは、'*' または ';' で書き始めます。どち
  32.  
  33. らを使っても構いませんが、1 つのプログラムの中では統一しておきましょう。
  34.  
  35.  
  36.  '*' はオペランドの先頭にも(ロケーションカウンタを参照するときに)書く
  37.  
  38. ことができるので、どちらかというと注釈の開始には ';' を使うことをお勧め
  39.  
  40. します。私も ';' を使っています。
  41.  
  42.  
  43. ●注釈の書き方のパターン
  44.  
  45.  行頭に '*' または ';' を書くと、その右側は行末まで注釈と見なされて無視
  46.  
  47. されます。
  48.  
  49.       ┌────────────────────────────
  50.       │;注釈
  51.  
  52.  行頭に空白があっても構いません。
  53.  
  54.       ┌────────────────────────────
  55.       │                ;注釈
  56.  
  57.  ラベルの後ろに空白を入れて書くこともできます。
  58.  
  59.       ┌────────────────────────────
  60.       │ラベル:                ;注釈
  61.  
  62.  命令や疑似命令あるいはマクロの後ろにも注釈を書くことができます。このと
  63.  
  64. きは、空白を入れてから、なるべく ';' で開始するようにして下さい。
  65.  
  66.       ┌────────────────────────────
  67.       │    命令            ;注釈
  68.       │ラベル:    命令            ;注釈
  69.  
  70.  オペランドの後に空白を入れて書くこともできます。オペランドの後に空白が
  71.  
  72. あるときはそれ以降は '*' や ';' がなくても無視されますが、注釈は '*' ま
  73.  
  74. たは ';' で書き始めるように心がけて下さい。
  75.  
  76.       ┌────────────────────────────
  77.       │    命令    オペランド    ;注釈
  78.       │ラベル:    命令    オペランド    ;注釈
  79.  
  80.  
  81. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  82.  
  83.     ':'(コロン)の使い方
  84.  
  85. ────────────────────────────────────
  86.  
  87.  一般的に、行頭のラベルの末尾には ':' を付ける習慣があります。
  88.  
  89.       ┌────────────────────────────
  90.       │foo:
  91.       ~
  92.  
  93. という具合です。ここで、ラベルと ':' の間を空けてはいけません。なお、こ
  94.  
  95. の書き方では命令や疑似命令あるいはマクロと同名のラベルを定義することがで
  96.  
  97. きます。
  98.  
  99.  
  100.  行頭から始まっていれば(ラベルの左側に空白がなければ)':' がなくてもラ
  101.  
  102. ベルと見なされます。
  103.  
  104.       ┌────────────────────────────
  105.       │foo
  106.       ~
  107.  
  108. でもよいわけです。ただし、この方法で命令や疑似命令あるいはマクロなどと同
  109.  
  110. 名のラベルを定義するときは、同じ行の右側に命令や疑似命令あるいはマクロを
  111.  
  112. 書くことで行頭の単語が命令などでないことを明確にする必要があります。
  113.  
  114.  
  115.  逆に、行頭から始まっていなくても(ラベルの左側に空白があっても)':' が
  116.  
  117. 付いていればラベルと見なされます。
  118.  
  119.       ┌────────────────────────────
  120.       │    char:=$61
  121.       │    .dc.b    char
  122.  
  123. これは char というシンボルに疑似命令 '='(疑似命令 set の別名)で $61 と
  124.  
  125. いう値を与えています。2 行目の .dc.b で埋め込まれる値は $61(文字で言う
  126.  
  127. と 'a')です。
  128.  
  129.  
  130.  HAS060.X に添付されている HANOI.S や K_MACRO.MAC が、行頭に空白を入れ
  131.  
  132. て ':' を付けてラベルを定義する記法を使っているので、参考にして下さい。
  133.  
  134.  
  135.  なお、行頭のシンボルに定数を与える equ、set、=(set の別名)、reg、
  136.  
  137. fequ、fset などでは、':' を付けないほうが一般的です。
  138.  
  139.  
  140. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  141.  
  142.     ローカルラベルの使い方
  143.  
  144. ────────────────────────────────────
  145.  
  146.  多くの細かい分岐やループを記述するのに、いちいちジャンプ先のラベルを考
  147.  
  148. えるのは面倒です。ラベルを幾つも書いているとだんだんハナモゲラになってし
  149.  
  150. まい、どこでどのラベルを参照しているのかがひと目でわからなくなってしまう
  151.  
  152. こともあります。
  153.  
  154.  
  155.  そこで、HAS.X や HAS060.X では名無しのローカルラベルが使えるようになっ
  156.  
  157. ています。名無しですが、ハナモゲラのラベルと比べればすぐ近くのジャンプ先
  158.  
  159. がわかりやすく、便利なものです。
  160.  
  161.  
  162.  ローカルラベルと言っても、スコープ(ラベルを参照できる範囲)に明確な制
  163.  
  164. 限があるわけではありません。「同種の名無しローカルラベルが複数定義されて
  165.  
  166. いるときは、前後どちらかの指定された方向で一番近くにあるものを参照する」
  167.  
  168. という単純な決まりがあるだけです。
  169.  
  170.  
  171.  名無しのローカルラベルをあまり遠いところから参照すると可読性の悪いソー
  172.  
  173. スになってしまうので注意しましょう。
  174.  
  175.  
  176.  なお、ここで説明するローカルラベルは、マクロ内ローカルラベル(後述)と
  177.  
  178. は関係ありません。
  179.  
  180.  
  181. ● '@@'
  182.  
  183.  ローカルラベル '@@' は、直前の '@f' または直後の '@b' から参照できます。
  184.  
  185.       ┌────────────────────────────
  186.       │    bra    @f    ────┐
  187.       │@@:            ←───┘
  188.       │@@:            ←───┐
  189.       │    bra    @b    ────┘
  190.  
  191.  なお、f は forward、b は backward の頭文字です。f や b は大文字で書い
  192.  
  193. ても同じ意味になります。
  194.  
  195.  
  196.  「一番近くにあるものを参照する」と書きましたが、@@: の場合は 2 番目、3
  197.  
  198. 番目と離れているものを参照することもできます。'@@f' は 2 つ後の '@@' を、
  199.  
  200. '@@b' は 2 つ前の '@@' を参照できます。
  201.  
  202.       ┌────────────────────────────
  203.       │    bra    @@f        ────┐
  204.       │@@:                ←───┼┐
  205.       │@@:                ←───┘│
  206.       │    bra    @@b        ─────┘
  207.  
  208.  
  209.  '@@@f' や '@@@b' なども同様に 1 つずつ離れてゆきます。
  210.  
  211.  
  212.  255 個まで離れている @@: を参照できるようになっていますが、実際には 2
  213.  
  214. つ以上離れている @@: を参照することはほとんどありません。2 つ以上離れる
  215.  
  216. ときは数字ローカルラベルを使ったほうが見やすいからです。
  217.  
  218.  
  219. ●数字ローカルラベル
  220.  
  221.  数字ローカルラベル '1' は、直前の '1f' または直後の '1b' から参照でき
  222.  
  223. ます。'2'、'3'、…も同様です。
  224.  
  225.  
  226.  HAS.X では '1' から '9' まで、HAS060.X では '1' から '9999' まで使えま
  227.  
  228. す。1 桁だと足りなくなることがありますが、普通は 2 桁もあれば足りると思
  229.  
  230. います。
  231.  
  232.     GRAM(65536 色モード)を buffer にコピーする
  233.       ┌────────────────────────────
  234.       │    lea.l    $00C00000,a0
  235.       │    lea.l    buffer,a1
  236.       │    move.w    #512-1,d2    ←────┐
  237.       │2:    move.w    #512-1,d1    ←───┐│
  238.       │1:    move.w    (a0)+,(a1)+        ││
  239.       │    dbra    d1,1b        ────┘│
  240.       │    dbra    d2,2b        ─────┘
  241.       ~
  242.       │buffer:
  243.       │    .dc.w    512*512
  244.  
  245.  
  246.  特定の数字ローカルラベルに意味を持たせておくと便利です。例えば、私はサ
  247.  
  248. ブルーチンの終了位置に 99: を置くようにしています。S44PLAY.X のソースで
  249.  
  250. も数字ローカルラベルを大量に使用しているので参考にして下さい。
  251.  
  252.  
  253. ●ローカルラベルの実装方法
  254.  
  255.  使い方とは関係ありませんが、ローカルラベルの機能の理解を助けるために、
  256.  
  257. HAS.X や HAS060.X における名無しのローカルラベルの実装方法を説明します。
  258.  
  259.  
  260.  HAS.X では 10 種類、HAS060.X では 10000 種類の名無しローカルラベルを使
  261.  
  262. えるようになっていますが、アセンブラの内部にそれぞれ今まで何回使われたか
  263.  
  264. を数えているワークがあります。初期状態はすべて 0 回になっています。
  265.  
  266.     @@:    0 回
  267.     1:    0 回
  268.     2:    0 回
  269.         :
  270.  
  271.  
  272.  この状態で例えば @@: というローカルラベルの定義が出てきたときは、それ
  273.  
  274. が自動的に @@#0: というラベルに置き換えられると考えて下さい(実際に @@#0
  275.  
  276. という名前が付けられるわけではありませんが、意味としてはそういうことです)。
  277.  
  278. そして @@: の使用回数が 1 回増えて 1 回になります。同様に、2 番目に出て
  279.  
  280. きた @@: は @@#1: になります。これが、同じ @@: というラベルを何度も定義
  281.  
  282. できる仕掛けです。要するに内部で順番に番号を振っているだけです。
  283.  
  284.       ┌────────────────────────────
  285.       │@@: → @@#0:
  286.       │@@: → @@#1:
  287.  
  288.  
  289.  さて、次に @f と @b がどうなっているのか説明しましょう。例えば @@: が
  290.  
  291. 既に 2 回出てきているとき、ローカルラベルのカウンタは次のようになってい
  292.  
  293. ます。
  294.  
  295.     @@:    2 回
  296.  
  297. このとき、@f: は現在のカウンタの番号の @@: を参照します。つまり、@f とい
  298.  
  299. うラベル参照は @@#2 というラベル参照に置き換えられるのです。@@#2: という
  300.  
  301. ラベルは直後に出てきた @@: に対して割り当てられるので、@f は直後の @@:
  302.  
  303. を参照することができるというわけです。同様に、@b は現在のカウンタの番号
  304.  
  305. から 1 を引いた @@: を参照します。つまり、今まで @@: が 2 回出てきた状態
  306.  
  307. で使用された @b は、@@#1: というラベル参照に置き換えられます。
  308.  
  309.       ┌────────────────────────────
  310.       │@@: → @@#0:
  311.       │@@: → @@#1:            ←────┐
  312.       │    bra    @f → @@#2:    ────┐│
  313.       │    bra    @b → @@#1:    ────┼┘
  314.       │@@: → @@#2:            ←───┘
  315.  
  316.  
  317.  まとめると、
  318.  
  319.                 :
  320.     @@@b    @@#(@@:の現在のカウンタ-3) を参照
  321.     @@b    @@#(@@:の現在のカウンタ-2) を参照
  322.     @b    @@#(@@:の現在のカウンタ-1) を参照
  323.     @f    @@#(@@:の現在のカウンタ+0) を参照
  324.     @@f    @@#(@@:の現在のカウンタ+1) を参照
  325.     @@@f    @@#(@@:の現在のカウンタ+2) を参照
  326.                 :
  327.  
  328. ということになります。
  329.  
  330.  
  331.  数字ローカルラベルでも同様です。
  332.  
  333.     1b    1#(1:の現在のカウンタ-1) を参照
  334.     1f    1#(1:の現在のカウンタ+0) を参照
  335.     2b    2#(2:の現在のカウンタ-1) を参照
  336.     2f    2#(2:の現在のカウンタ+0) を参照
  337.                 :
  338.     9999b    9999#(9999:の現在のカウンタ-1) を参照
  339.     9999f    9999#(9999:の現在のカウンタ+0) を参照
  340.  
  341.  
  342.  HAS060.X は 10000 種類のローカルラベルを使用できるようになっているので、
  343.  
  344. カウンタのワークだけで 20KB 近く消費しています。
  345.  
  346.  
  347. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  348.  
  349.     ラベルを自動的に外部定義にする
  350.  
  351. ────────────────────────────────────
  352.  
  353.  ラベルに付ける ':' を 2 つ繋げて '::' と書くと、そのラベルが自動的に外
  354.  
  355. 部定義になります。
  356.  
  357.  
  358.  ラベルを外部定義にしたいときは .xdef などを使って定義することもできま
  359.  
  360. すが、'::' を使うと便利です。
  361.  
  362.       ┌────────────────────────────
  363.       │    .xdef    foo
  364.       │foo:
  365.  
  366.  
  367.       ┌────────────────────────────
  368.       │foo::
  369.  
  370. は同じ意味です。
  371.  
  372.  
  373. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  374.  
  375.     疑似命令の先頭に付ける '.' の意味
  376.  
  377. ────────────────────────────────────
  378.  
  379.  アセンブラでは疑似命令を '.' で始めるという習慣があります。
  380.  
  381.       ┌────────────────────────────
  382.       │    .text
  383.       │    .even
  384.       ~
  385.  
  386. などと書くわけです。
  387.  
  388.  
  389.  しかし、疑似命令に '.' を付けなければいけないという決まりがあるわけで
  390.  
  391. はありません。逆に、普通の命令に '.' を付けてもエラーにはなりません。
  392.  
  393.  
  394.  命令や疑似命令の先頭に '.' を付けたときと付けないときでは、次のような
  395.  
  396. 違いがあります。
  397.  
  398.     命令や疑似命令と同名のマクロが定義されているとき、
  399.  
  400.       '.' を付けたとき・・・・・・・命令や疑似命令を優先する
  401.  
  402.       '.' を付けなかったたとき・・・マクロを優先する
  403.  
  404.  
  405.  例えば、次の例を見て下さい。
  406.  
  407.       ┌────────────────────────────
  408.       │bra    .macro    lab
  409.       │    bra.w    lab
  410.       │    .endm
  411.       │    bra    main
  412.       ~
  413.       │main:
  414.       ~
  415.  
  416. このプログラムでは bra 命令を強制的にワードサイズにするマクロを定義しよ
  417.  
  418. うとしています。しかし、このままでは期待通りにアセンブルされません。マク
  419.  
  420. ロの中の「bra.w lab」のところで再び bra マクロ(=自分自身)を呼び出して
  421.  
  422. しまうので、「マクロのネストが深すぎます」というエラーが出てしまうのです。
  423.  
  424. そこで、マクロを次のように書き換えます。
  425.  
  426.       ┌────────────────────────────
  427.       │bra    .macro    lab
  428.     →│    .bra.w    lab
  429.       │    .endm
  430.       │    bra    main
  431.       ~
  432.       │main:
  433.       ~
  434.  
  435. 変更したのは、2 行目の bra.w の先頭に '.' を付けただけです。これだけでこ
  436.  
  437. の bra.w はマクロよりも命令を優先して解釈されることになるので、自分自身
  438.  
  439. を再帰的に呼び出すことはなくなり、期待通りにアセンブルされます。
  440.  
  441.  
  442.  上記の例のような特別な場合以外は、「疑似命令には '.' を付け、命令とマ
  443.  
  444. クロには '.' を付けない」という習慣に従いましょう。ただし、行頭のシンボ
  445.  
  446. ルに定数を与える equ、set、=(set の別名)、reg、fequ、fset などには '.'
  447.  
  448. を付けないほうが一般的です。
  449.  
  450.  
  451. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  452.  
  453.     便利な疑似命令 reg
  454.  
  455. ────────────────────────────────────
  456.  
  457.  マニュアルでは reg はシンボルにレジスタリストを割り付ける疑似命令とい
  458.  
  459. うことになっていますが、実際にはレジスタリストに限らず、命令のオペランド
  460.  
  461. に書くことができる文字列ならば何でもシンボルに割り付けることができます。
  462.  
  463.  
  464.  つまり、実は reg はシンボルに任意のオペランドを割り付ける疑似命令なの
  465.  
  466. です。
  467.  
  468.  
  469.  一般的な使い方としては、サブルーチンでスタックにセーブするレジスタをシ
  470.  
  471. ンボルに覚えさせておくときに使います。
  472.  
  473.       ┌────────────────────────────
  474.       │save_regs    reg    d3-d7/a3-a6
  475.       │subroutine:
  476.       │    movem.l    save_regs,-(sp)
  477.       ~
  478.       │    movem.l    (sp)+,save_regs
  479.       │    rts
  480.  
  481. こうすると、「プログラムを書き換えているうちにプッシュするレジスタとポッ
  482.  
  483. プするレジスタの数や種類が食い違ってしまった」などという間違いを減らせま
  484.  
  485. す。
  486.  
  487.  
  488.  しかし、私がよく使う使い方はこれです。
  489.  
  490.       ┌────────────────────────────
  491.       │PROGNAME    reg    'S44PLAY'
  492.       │VERSION        reg    '1.02'
  493.       │DATE        reg    '2000.03.11'
  494.       ~
  495.       │banner:
  496.       │    .dc.b    PROGNAME,'.X v',VERSION,' (',DATE,') by M.Kamada',0
  497.       ~
  498.  
  499. banner のところの文字列は「S44PLAY.X v1.02 (2000.03.11) by M.Kamada」と
  500.  
  501. なります。
  502.  
  503.  
  504.  上の例では、reg の「オペランドなら何でも代入できる」という特徴を活かし
  505.  
  506. て、シンボルに文字列を割り当てています。このようにプログラムの先頭でプロ
  507.  
  508. グラムのバージョンや日付をシンボルに割り当てておくと、後で更新するときに
  509.  
  510. いちいちプログラム中の文字列データを探して書き換えなくて済むので便利です。
  511.  
  512.  
  513. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  514.  
  515.     くり返し その1(.rept~.endm)
  516.  
  517. ────────────────────────────────────
  518.  
  519.  .rept はその名の通り、指定されたブロックを指定された回数だけ繰り返して
  520.  
  521. アセンブルする疑似命令です。
  522.  
  523.  
  524.  例えば、テキスト VRAM に半角フォントを書き込むときは次のように書くこと
  525.  
  526. ができます。
  527.  
  528.       ┌────────────────────────────
  529.       │;<a0.l:テキストVRAMアドレス
  530.       │;<a1.l:8×16ドットフォントアドレス
  531.       │d = 0
  532.       │  .rept 16
  533.       │    move.b    (a1)+,(d,a0)
  534.       │d = d+128
  535.       │  .endm
  536.  
  537. テキスト VRAM の Y 方向 1 ドットのオフセットは 128 なので、デスティネー
  538.  
  539. ションのディスプレースメントを 128 ずつ増やしながら 16 回書き込んでいま
  540.  
  541. す。
  542.  
  543.  
  544.  アセンブル時にコマンドラインに -p -f,1 を指定してアセンブルリストを出
  545.  
  546. 力させてみると、.rept の挙動がよくわかります。
  547.  
  548.       ┌────────────────────────────
  549.       ~
  550.       │<test.s>
  551.       │    1 00000000                  ;<a0.l:テキストVRAMアドレス
  552.       │    2 00000000                  ;<a1.l:8×16ドットフォントアドレス
  553.       │    3 00000000 =00000000        d = 0
  554.       │    4 00000000                    .rept 16
  555.       │    5 00000000                      move.b    (a1)+,(d,a0)
  556.       │    6 00000000                  d = d+128
  557.       │    7 00000000                    .endm
  558.       │    7 00000000*1099                 move.b    (a1)+,(d,a0)
  559.       │    7 00000002*=00000080        d = d+128
  560.       │    7 00000002*11590080             move.b    (a1)+,(d,a0)
  561.       │    7 00000006*=00000100        d = d+128
  562.       │    7 00000006*11590100             move.b    (a1)+,(d,a0)
  563.       │    7 0000000A*=00000180        d = d+128
  564.       │    7 0000000A*11590180             move.b    (a1)+,(d,a0)
  565.       │    7 0000000E*=00000200        d = d+128
  566.       │    7 0000000E*11590200             move.b    (a1)+,(d,a0)
  567.       │    7 00000012*=00000280        d = d+128
  568.       │    7 00000012*11590280             move.b    (a1)+,(d,a0)
  569.       │    7 00000016*=00000300        d = d+128
  570.       │    7 00000016*11590300             move.b    (a1)+,(d,a0)
  571.       │    7 0000001A*=00000380        d = d+128
  572.       │    7 0000001A*11590380             move.b    (a1)+,(d,a0)
  573.       │    7 0000001E*=00000400        d = d+128
  574.       │    7 0000001E*11590400             move.b    (a1)+,(d,a0)
  575.       │    7 00000022*=00000480        d = d+128
  576.       │    7 00000022*11590480             move.b    (a1)+,(d,a0)
  577.       │    7 00000026*=00000500        d = d+128
  578.       │    7 00000026*11590500             move.b    (a1)+,(d,a0)
  579.       │    7 0000002A*=00000580        d = d+128
  580.       │    7 0000002A*11590580             move.b    (a1)+,(d,a0)
  581.       │    7 0000002E*=00000600        d = d+128
  582.       │    7 0000002E*11590600             move.b    (a1)+,(d,a0)
  583.       │    7 00000032*=00000680        d = d+128
  584.       │    7 00000032*11590680             move.b    (a1)+,(d,a0)
  585.       │    7 00000036*=00000700        d = d+128
  586.       │    7 00000036*11590700             move.b    (a1)+,(d,a0)
  587.       │    7 0000003A*=00000780        d = d+128
  588.       │    7 0000003A*11590780             move.b    (a1)+,(d,a0)
  589.       │    7 0000003E*=00000800        d = d+128
  590.       ~
  591.  
  592. 1 回目は d = 0 なので (d,a0) が (a0) に変換されることにも注目して下さい。
  593.  
  594.  
  595. ● .rept~.endm の実装方法
  596.  
  597.  .rept~.endm は名無しマクロの一種です。.rept からマクロの定義が開始さ
  598.  
  599. れ、.endm が出てきたら自動的にそこまでのコードを .rept で指定された回数
  600.  
  601. だけ繰り返して展開しているだけなのです。
  602.  
  603.  
  604.  .rept の内部で発生したアセンブルエラーの多くが .endm の行で通知される
  605.  
  606. のは、マクロの内部で発生したアセンブルエラーがほとんどマクロの定義のとき
  607.  
  608. ではなくてマクロの展開のときに発生するのと同じことです。
  609.  
  610.  
  611. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  612.  
  613.     くり返し その2(.irp~.endm)
  614.  
  615. ────────────────────────────────────
  616.  
  617.  .irp もループ展開を行う疑似命令です。.rept と違い、.irp では 1 回展開
  618.  
  619. する毎に特定のシンボルに指定された文字列を割り当てることができます。1 つ
  620.  
  621. の引数を持つ名無しマクロに毎回異なる引数を与えて展開する、と言ったほうが
  622.  
  623. わかりやすいかも知れません。
  624.  
  625.  
  626.  .irp の最初の引数はその .irp~.endm の中だけで有効なシンボルです。その
  627.  
  628. シンボルに 2 番目以降の引数が順に代入されながら、.irp~.endm の中のコー
  629.  
  630. ドが繰り返し展開されます。
  631.  
  632.       ┌────────────────────────────
  633.       │  .irp rgb,red,green,blue
  634.       │str_&rgb:    .dc.b    '&rgb',0
  635.       │  .endm
  636.  
  637. この場合は rgb というシンボルに red、green、blue が順に代入されます。展
  638.  
  639. 開結果は、
  640.  
  641.       ┌────────────────────────────
  642.       │    3 00000000*72656400         str_red:    .dc.b    'red',0
  643.       │    3 00000004*677265656E00     str_green:    .dc.b    'green',0
  644.       │    3 0000000A*626C756500       str_blue:    .dc.b    'blue',0
  645.  
  646.  
  647.  .irp~.endm の中では、マクロの場合と同様に &シンボル の形式で引数を参
  648.  
  649. 照できます。シンボルが独立しているときは '&' は無くても構いません。
  650.  
  651.  
  652. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  653.  
  654.     くり返し その3(.irpc~.endm)
  655.  
  656. ────────────────────────────────────
  657.  
  658.  .irpc は .irp の変化形です。.irp が 2 番目以降の引数を順にシンボルに割
  659.  
  660. り当ててゆくのに対して、.irpc は 2 番目の引数の文字を 1 文字ずつ順にシン
  661.  
  662. ボルに割り当ててゆきます。
  663.  
  664.       ┌────────────────────────────
  665.       │ea_jump_table:
  666.       │  .irpc rrr,01234567
  667.       │    .irpc mmm,01234567
  668.       │    .dc.w    ea_&rrr&&mmm-ea_jump_table
  669.       │    .endm
  670.       │  .endm
  671.  
  672. .irpc を二重に使っているので、外側のループの引数の rrr の参照は &rrr で、
  673.  
  674. 内側のループの引数の mmm の参照が &&mmm になっていることに注目して下さい。
  675.  
  676. 外側のループが展開された時点で、&&mmm が &mmm に変化し、さらに内側のルー
  677.  
  678. プが展開されるときに &mmm が文字に置き換わります。展開結果は、
  679.  
  680.       ┌────────────────────────────
  681.       │    1 00000000                  ea_jump_table:
  682.       │    2 00000000                    .irpc rrr,01234567
  683.       │    3 00000000                      .irpc mmm,01234567
  684.       │    4 00000000                      .dc.w    ea_&rrr&&mmm-ea_jump_table
  685.       │    5 00000000                      .endm
  686.       │    6 00000000                    .endm
  687.       │    6 00000000*                     .irpc mmm,01234567
  688.       │    6 00000000*                     .dc.w    ea_0&mmm-ea_jump_table
  689.       │    6 00000000*                     .endm
  690.       │    6 00000000*????                 .dc.w    ea_00-ea_jump_table
  691.       │    6 00000002*????                 .dc.w    ea_01-ea_jump_table
  692.       │    6 00000004*????                 .dc.w    ea_02-ea_jump_table
  693.       │    6 00000006*????                 .dc.w    ea_03-ea_jump_table
  694.       │    6 00000008*????                 .dc.w    ea_04-ea_jump_table
  695.       │    6 0000000A*????                 .dc.w    ea_05-ea_jump_table
  696.       │    6 0000000C*????                 .dc.w    ea_06-ea_jump_table
  697.       │    6 0000000E*????                 .dc.w    ea_07-ea_jump_table
  698.       │    6 00000010*                     .irpc mmm,01234567
  699.       │    6 00000010*                     .dc.w    ea_1&mmm-ea_jump_table
  700.       │    6 00000010*                     .endm
  701.       │    6 00000010*????                 .dc.w    ea_10-ea_jump_table
  702.       │    6 00000012*????                 .dc.w    ea_11-ea_jump_table
  703.       │    6 00000014*????                 .dc.w    ea_12-ea_jump_table
  704.       │    6 00000016*????                 .dc.w    ea_13-ea_jump_table
  705.       ~
  706.       │    6 00000070*                     .irpc mmm,01234567
  707.       │    6 00000070*                     .dc.w    ea_7&mmm-ea_jump_table
  708.       │    6 00000070*                     .endm
  709.       │    6 00000070*????                 .dc.w    ea_70-ea_jump_table
  710.       │    6 00000072*????                 .dc.w    ea_71-ea_jump_table
  711.       │    6 00000074*????                 .dc.w    ea_72-ea_jump_table
  712.       │    6 00000076*????                 .dc.w    ea_73-ea_jump_table
  713.       │    6 00000078*????                 .dc.w    ea_74-ea_jump_table
  714.       │    6 0000007A*????                 .dc.w    ea_75-ea_jump_table
  715.       │    6 0000007C*????                 .dc.w    ea_76-ea_jump_table
  716.       │    6 0000007E*????                 .dc.w    ea_77-ea_jump_table
  717.  
  718. ここでは ea_00 などのシンボルが未定義なので値は ???? になっています。
  719.  
  720.  
  721.  .irpc の 2 番目の引数が '~' で囲まれているときは、'~' の中の文字列だ
  722.  
  723. けが文字を取り出す対象になります。
  724.  
  725.  
  726.  こんなこともできます。
  727.  
  728.       ┌────────────────────────────
  729.       │foo    .macro    str
  730.       │  .irpc c,str
  731.       │    .if ('a'<='&c').and.('&c'<='z')
  732.       │    .dc.b    '&c'.and.$df
  733.       │    .else
  734.       │    .dc.b    '&c'
  735.       │    .endif
  736.       │  .endm
  737.       │    .endm
  738.       │    foo    'm68k'
  739.  
  740. 何をやっているか、だいたい予想がつくでしょうか?
  741.  
  742.       ┌────────────────────────────
  743.       │<test.s>
  744.       │    1 00000000                  foo    .macro    str
  745.       │    2 00000000                    .irpc c,str
  746.       │    3 00000000                      .if ('a'<='&c').and.('&c'<='z')
  747.       │    4 00000000                      .dc.b    '&c'.and.$df
  748.       │    5 00000000                      .else
  749.       │    6 00000000                      .dc.b    '&c'
  750.       │    7 00000000                      .endif
  751.       │    8 00000000                    .endm
  752.       │    9 00000000                      .endm
  753.       │   10 00000000                      foo    'm68k'
  754.       │   10 00000000*                   .irpc c,'m68k'
  755.       │   10 00000000*                     .if ('a'<='&c').and.('&c'<='z')
  756.       │   10 00000000*                     .dc.b    '&c'.and.$df
  757.       │   10 00000000*                     .else
  758.       │   10 00000000*                     .dc.b    '&c'
  759.       │   10 00000000*                     .endif
  760.       │   10 00000000*                   .endm
  761.       │   10 00000000*                     .if ('a'<='m').and.('m'<='z')
  762.       │   10 00000000*4D                   .dc.b    'm'.and.$df
  763.       │   10 00000001*                     .else
  764.       │   10 00000001*                     .dc.b    'm'
  765.       │   10 00000001*                     .endif
  766.       │   10 00000001*                     .if ('a'<='6').and.('6'<='z')
  767.       │   10 00000001*                     .dc.b    '6'.and.$df
  768.       │   10 00000001*                     .else
  769.       │   10 00000001*36                   .dc.b    '6'
  770.       │   10 00000002*                     .endif
  771.       │   10 00000002*                     .if ('a'<='8').and.('8'<='z')
  772.       │   10 00000002*                     .dc.b    '8'.and.$df
  773.       │   10 00000002*                     .else
  774.       │   10 00000002*38                   .dc.b    '8'
  775.       │   10 00000003*                     .endif
  776.       │   10 00000003*                     .if ('a'<='k').and.('k'<='z')
  777.       │   10 00000003*4B                   .dc.b    'k'.and.$df
  778.       │   10 00000004*                     .else
  779.       │   10 00000004*                     .dc.b    'k'
  780.       │   10 00000004*                     .endif
  781.  
  782. 「指定された文字列を 1 文字ずつ分解して、それぞれの文字が 'a'~'z' の範
  783.  
  784. 囲内なら $df と .and. したものを、そうでなければその文字をそのまま出力す
  785.  
  786. る」、つまり、「文字列を大文字化して出力するマクロ」です。
  787.  
  788.  
  789. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  790.  
  791.     マクロ内ローカルラベル
  792.  
  793. ────────────────────────────────────
  794.  
  795.  .macro~.endm で定義されたマクロの中では、疑似命令 .local を使ってその
  796.  
  797. マクロの中だけで有効なラベルを定義することができます。
  798.  
  799.  
  800.  例えば、指定された回数だけ指定されたサブルーチンを呼び出すマクロは次の
  801.  
  802. ように定義できます。
  803.  
  804.       ┌────────────────────────────
  805.       │repeat    .macro    n,lab
  806.       │    .local    loop
  807.       │    move.w    #n,-(sp)
  808.       │loop:
  809.       │    jsr    lab
  810.       │    subq.w    #1,(sp)
  811.       │    bne    loop
  812.       │    addq.l    #2,sp
  813.       │    .endm
  814.       ~
  815.       │    repeat    10,subroutine
  816.  
  817.  
  818.  さて、マクロ内ローカルラベルの数が多くなってくると、いちいち .local で
  819.  
  820. ラベルを宣言するのは面倒です。そこで、HAS060.X にはマクロ内ローカルラベ
  821.  
  822. ルが自動的に宣言されるという便利な機能が追加されています。マクロの中では
  823.  
  824. '@' で始まるラベルを使用すると、勝手にマクロ内ローカルラベルになるのです。
  825.  
  826. ただし、@f、@F、@b、@B および @@~ で始まるラベルはマクロ内ローカルラベ
  827.  
  828. ルとしては使えません。
  829.  
  830.       ┌────────────────────────────
  831.       │repeat    .macro    n,lab
  832.       │    move.w    #n,-(sp)
  833.       │@loop:
  834.       │    jsr    lab
  835.       │    subq.w    #1,(sp)
  836.       │    bne    @loop
  837.       │    addq.l    #2,sp
  838.       │    .endm
  839.       ~
  840.       │    repeat    10,subroutine
  841.  
  842.  
  843.  マクロ内ローカルシンボルを大量に使用しているプログラムの例としては、
  844.  
  845. S44PLAY.X の core.s などがあります。
  846.  
  847.  
  848. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  849.  
  850.     オペレーションサイズを解釈するマクロ
  851.  
  852. ────────────────────────────────────
  853.  
  854.  命令に近い形のマクロを定義することができるようにするために、HAS060.X
  855.  
  856. ではマクロの使用時に指定されたオペレーションサイズをマクロの中で使用する
  857.  
  858. ことができるようになっています。
  859.  
  860.  
  861.  マクロ定義の先頭で .sizem を使ってシンボルを宣言することで、マクロに指
  862.  
  863. 定されたオペレーションサイズを .sizem で指定したシンボルで受け取ることが
  864.  
  865. できます。
  866.  
  867.       ┌────────────────────────────
  868.       │inc    .macro    ea
  869.       │    .sizem    sz
  870.       │    addq&sz    #1,ea
  871.       │    .endm
  872.       │    inc.l    d0
  873.       │    inc    (a0)+
  874.  
  875. 展開結果は、
  876.  
  877.       ┌────────────────────────────
  878.       │    5 00000000                      inc.l    d0
  879.       │    5 00000000*5280                 addq.l    #1,d0
  880.       │    6 00000002                      inc    (a0)+
  881.       │    6 00000002*5258                 addq      #1,(a0)+
  882.  
  883.  
  884.  なお、.sizem はマクロに指定された引数の個数を受け取るシンボルを宣言す
  885.  
  886. ることもできます。詳しくは HAS060.X のマニュアルを参照して下さい。
  887.  
  888.  
  889. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  890.  
  891.     cc と Ncc
  892.  
  893. ────────────────────────────────────
  894.  
  895.  ここで言う cc というのは、Bcc や DBcc と書くときの cc、つまり、ニモニ
  896.  
  897. ックの中のコンディションコードを表す部分のことです。HAS060.X には、cc の
  898.  
  899. 代わりに Ncc を指定することで条件を逆にする機能があります。
  900.  
  901.       ┌────────────────────────────
  902.       │  .irp cc,hi,ls,cc,hs,cs,lo,ne,eq,vc,vs,pl,mi,ge,lt,gt,le
  903.       │if&cc    .macro    cmd
  904.       │    bn&cc    @skip
  905.       │    cmd
  906.       │@skip:
  907.       │    .endm
  908.       │  .endm
  909.       │    tst.l    d0
  910.       │    ifmi    <neg.l d0>
  911.  
  912. .irp~.endm の中に .macro~.endm があることにも注目。これで一度に大量の
  913.  
  914. マクロを定義しています。-p -f,1 でアセンブルしてみると、以下のようなアセ
  915.  
  916. ンブルリストが得られます。
  917.  
  918.       ┌────────────────────────────
  919.       │<test.s>
  920.       │    1 00000000                    .irp cc,hi,ls,cc,hs,cs,lo,ne,eq,vc,vs,pl,mi,ge,lt,gt,le
  921.       │    2 00000000                  if&cc    .macro    cmd
  922.       │    3 00000000                      bn&cc    @skip
  923.       │    4 00000000                      cmd
  924.       │    5 00000000                  @skip:
  925.       │    6 00000000                      .endm
  926.       │    7 00000000                    .endm
  927.       │    7 00000000*                 ifhi    .macro    cmd
  928.       │    7 00000000*                     bnhi    @skip
  929.       │    7 00000000*                     cmd
  930.       │    7 00000000*                 @skip:
  931.       │    7 00000000*                     .endm
  932.       │    7 00000000*                 ifls    .macro    cmd
  933.       │    7 00000000*                     bnls    @skip
  934.       │    7 00000000*                     cmd
  935.       │    7 00000000*                 @skip:
  936.       │    7 00000000*                     .endm
  937.       │    7 00000000*                 ifcc    .macro    cmd
  938.       │    7 00000000*                     bncc    @skip
  939.       │    7 00000000*                     cmd
  940.       │    7 00000000*                 @skip:
  941.       │    7 00000000*                     .endm
  942.       │    7 00000000*                 ifhs    .macro    cmd
  943.       │    7 00000000*                     bnhs    @skip
  944.       │    7 00000000*                     cmd
  945.       │    7 00000000*                 @skip:
  946.       │    7 00000000*                     .endm
  947.       │    7 00000000*                 ifcs    .macro    cmd
  948.       │    7 00000000*                     bncs    @skip
  949.       │    7 00000000*                     cmd
  950.       │    7 00000000*                 @skip:
  951.       │    7 00000000*                     .endm
  952.       │    7 00000000*                 iflo    .macro    cmd
  953.       │    7 00000000*                     bnlo    @skip
  954.       │    7 00000000*                     cmd
  955.       │    7 00000000*                 @skip:
  956.       │    7 00000000*                     .endm
  957.       │    7 00000000*                 ifne    .macro    cmd
  958.       │    7 00000000*                     bnne    @skip
  959.       │    7 00000000*                     cmd
  960.       │    7 00000000*                 @skip:
  961.       │    7 00000000*                     .endm
  962.       │    7 00000000*                 ifeq    .macro    cmd
  963.       │    7 00000000*                     bneq    @skip
  964.       │    7 00000000*                     cmd
  965.       │    7 00000000*                 @skip:
  966.       │    7 00000000*                     .endm
  967.       │    7 00000000*                 ifvc    .macro    cmd
  968.       │    7 00000000*                     bnvc    @skip
  969.       │    7 00000000*                     cmd
  970.       │    7 00000000*                 @skip:
  971.       │    7 00000000*                     .endm
  972.       │    7 00000000*                 ifvs    .macro    cmd
  973.       │    7 00000000*                     bnvs    @skip
  974.       │    7 00000000*                     cmd
  975.       │    7 00000000*                 @skip:
  976.       │    7 00000000*                     .endm
  977.       │    7 00000000*                 ifpl    .macro    cmd
  978.       │    7 00000000*                     bnpl    @skip
  979.       │    7 00000000*                     cmd
  980.       │    7 00000000*                 @skip:
  981.       │    7 00000000*                     .endm
  982.       │    7 00000000*                 ifmi    .macro    cmd
  983.       │    7 00000000*                     bnmi    @skip
  984.       │    7 00000000*                     cmd
  985.       │    7 00000000*                 @skip:
  986.       │    7 00000000*                     .endm
  987.       │    7 00000000*                 ifge    .macro    cmd
  988.       │    7 00000000*                     bnge    @skip
  989.       │    7 00000000*                     cmd
  990.       │    7 00000000*                 @skip:
  991.       │    7 00000000*                     .endm
  992.       │    7 00000000*                 iflt    .macro    cmd
  993.       │    7 00000000*                     bnlt    @skip
  994.       │    7 00000000*                     cmd
  995.       │    7 00000000*                 @skip:
  996.       │    7 00000000*                     .endm
  997.       │    7 00000000*                 ifgt    .macro    cmd
  998.       │    7 00000000*                     bngt    @skip
  999.       │    7 00000000*                     cmd
  1000.       │    7 00000000*                 @skip:
  1001.       │    7 00000000*                     .endm
  1002.       │    7 00000000*                 ifle    .macro    cmd
  1003.       │    7 00000000*                     bnle    @skip
  1004.       │    7 00000000*                     cmd
  1005.       │    7 00000000*                 @skip:
  1006.       │    7 00000000*                     .endm
  1007.       │    8 00000000 4A80                 tst.l    d0
  1008.       │    9 00000002                      ifmi    <neg.l d0>
  1009.       │    9 00000002*6A02_00000006        bnmi    ??0001
  1010.       │    9 00000004*4480                 neg.l d0
  1011.       │    9 00000006*                 ??0001:
  1012.  
  1013.  
  1014.  使用頻度は高くありませんが、Ncc はマクロで機械的に条件を入れ替えたいと
  1015.  
  1016. きに便利です。HAS060.X に添付されている K_MACRO.MAC でも大量に使用してい
  1017.  
  1018. ますので、参考にしてみて下さい。
  1019.  
  1020.  
  1021. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  1022.  
  1023.     JBRA、JBSR、JBcc
  1024.  
  1025. ────────────────────────────────────
  1026.  
  1027.  68000 では、bra 命令は bra.s と bra.w しか使えません。そのため、コード
  1028.  
  1029. が 32KB を越えるプログラムを書くとき、bra ではオフセットが届かなくなって
  1030.  
  1031. しまうことがあります。「jmp を使うとコードが長くなってしまう(3 ワード必
  1032.  
  1033. 要)のでなるべく bra(2 ワード)を使いたいけれど、どの分岐が bra で届く
  1034.  
  1035. かわからない」というときは、jbra を使うと便利です。
  1036.  
  1037.  
  1038.  jbra という命令は m68k の命令としては実在しません。アセンブラがオフセ
  1039.  
  1040. ットに応じて bra か jmp に自動的に読み代えます。jbsr も同様です。jbcc は、
  1041.  
  1042. bcc でオフセットが届かなければ、逆条件の bncc 命令で jsr や jmp 命令を飛
  1043.  
  1044. び越えるような 4 ワードの命令列が自動的に生成されます。
  1045.  
  1046.       ┌────────────────────────────
  1047.       │    jbhi    foo
  1048.       │  .rept 20000
  1049.       │    nop
  1050.       │  .endm
  1051.       │foo:
  1052.  
  1053. これを展開すると、
  1054.  
  1055.       ┌────────────────────────────
  1056.       │    1 00000000 63064EF9(01)0000     jbhi    foo
  1057.       │               9C48             
  1058.       │    2 00000008                    .rept 20000
  1059.       │    3 00000008                      nop
  1060.       │    4 00000008                    .endm
  1061.       │    5 00009C48                  foo:
  1062.  
  1063. となります。jbhi が 4 ワードの命令列に展開されていることがわかります。こ
  1064.  
  1065. の 4 ワードを逆アセンブルしてみるとわかりますが、jbhi の部分の 4 ワード
  1066.  
  1067. の命令は、次のようなコードになっています。
  1068.  
  1069.       ┌────────────────────────────
  1070.       │    bls.s    L000006
  1071.       │    jmp    foo
  1072.       │L000006:
  1073.  
  1074. bls のように分岐の条件が ls になっているのは、jbhi の hi の逆条件である
  1075.  
  1076. nhi というのが ls と等価だからです。この命令列で、「hi ならば jmp する」
  1077.  
  1078. という jbhi の機能を実現しているというわけです。
  1079.  
  1080.  
  1081. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  1082.  
  1083.     バイナリデータを埋め込む
  1084.  
  1085. ────────────────────────────────────
  1086.  
  1087.  アセンブラのソースの中にスプライトデータなどのバイナリデータを埋め込み
  1088.  
  1089. たいときがあります。16 進数でダンプして .dc.b や $ を付けて整形してもよ
  1090.  
  1091. いのですが、面倒なので、HAS060.X ではバイナリデータの入っているファイル
  1092.  
  1093. を直接プログラムに埋め込むことができるようにしました。
  1094.  
  1095.  
  1096.  疑似命令 .insert は指定されたファイルをバイナリデータと見なしてプログ
  1097.  
  1098. ラムに埋め込みます。埋め込むデータの範囲は指定できますが、データそのもの
  1099.  
  1100. は一切加工されません。
  1101.  
  1102.  
  1103.  電脳倶楽部 142 号に掲載した『ごーじゃすリバーシ』のソース(graph.s)で
  1104.  
  1105. .insert を有効に利用しているので引用します。
  1106.  
  1107.       ┌────────────────────────────
  1108.       │  .irp moji,0,1,2,3,4,5,6,7,8,9
  1109.       │spc&moji:    .insert    sp/&moji.sp
  1110.       │  .endm
  1111.       │  .irp moji,き,け,ち,の,ス,パ,ベ,ル,レ,引,局,後,黒,手,終,勝,石,先,対,白,分,了
  1112.       │spc&moji:    .insert    sp/&moji.sp
  1113.       │  .endm
  1114.  
  1115. アセンブルリストを吐かせると、挿入されたバイナリデータがすべて出てきます。
  1116.  
  1117.       ┌────────────────────────────
  1118.       │    1 00000000                    .irp moji,0,1,2,3,4,5,6,7,8,9
  1119.       │    2 00000000                  spc&moji:    .insert    sp/&moji.sp
  1120.       │    3 00000000                    .endm
  1121.       │    3 00000000*0000000000000000 spc0:    .insert    sp/0.sp
  1122.       │               0000000000000000 
  1123.       │               0000000000000000 
  1124.       │               0000000000000003 
  1125.       │               0000000A0000001F 
  1126.       │               0000005F0000008F 
  1127.       │               000000AF000000CF 
  1128.       │               000000DF000000FF 
  1129.       ~
  1130.       │    3 00000200*0000000000000000 spc1:    .insert    sp/1.sp
  1131.       ~
  1132.       │    4 00001400                    .irp moji,き,け,ち,の,ス,パ,ベ,ル,レ,引,局,後,黒,手,終,勝,石,先,対,白,分,了
  1133.       │    5 00001400                  spc&moji:    .insert    sp/&moji.sp
  1134.       │    6 00001400                    .endm
  1135.       │    6 00001400*0000000000000000 spcき:    .insert    sp/き.sp
  1136.       │               0000000000000000 
  1137.       │               0000000000000000 
  1138.       │               0000000000004444 
  1139.       │               00008FFF00008FFF 
  1140.       │               0000488600000000 
  1141.       │               00000000008ECCCC 
  1142.       │               008FFFFF008FFFFF 
  1143.       ~
  1144.       │    6 00003E00*0000000000000000 spc了:    .insert    sp/了.sp
  1145.       ~
  1146.  
  1147.  
  1148. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  1149.  
  1150.     .not. と .notb. と .notw.
  1151.  
  1152. ────────────────────────────────────
  1153.  
  1154.  .not. は単項演算子です。もっと詳しく言うと、ビット毎の論理否定演算子と
  1155.  
  1156. いうやつです。ですから、
  1157.  
  1158.     .not.$55555555 = $AAAAAAAA
  1159.     .not.$AAAAAAAA = $55555555
  1160.  
  1161. です。
  1162.  
  1163.  
  1164.  では、次のソースをアセンブルしたらどうなるでしょう?
  1165.  
  1166.       ┌────────────────────────────
  1167.       │    .dc.b    .not.$55
  1168.       │    .dc.b    .not.$AA
  1169.  
  1170. 答えは「1 行目が $AA で 2 行目が $55 になる」ですか? 残念ながらハズレ
  1171.  
  1172. です。アセンブルしてみるとわかりますが、2 行目だけエラーになります。
  1173.  
  1174.       ┌────────────────────────────
  1175.       │<test.s>
  1176.       │    1 00000000 AA                   .dc.b    .not.$55
  1177.       │test.s               2: Error: オーバーフローしました
  1178.       │    2 00000001                      .dc.b    .not.$AA
  1179.  
  1180.  
  1181.  理由は簡単、
  1182.  
  1183.     .not.$55 = $FFFFFFAA
  1184.     .not.$AA = $FFFFFF55
  1185.  
  1186. で、2 番目の $FFFFFF55 = -171 は .dc.b の引数に許される「符号なしまたは
  1187.  
  1188. 符号あり 8 ビット整数(具体的には -128~255)」の範囲外ということでオー
  1189.  
  1190. バーフローエラーになります。
  1191.  
  1192.  
  1193.  しかし、この少々分かり難い問題に遭遇してしまい、「アセンブラのバグでは
  1194.  
  1195. ないか?」と“バグ報告”を寄せて下さった方が何人かいらっしゃったのです。
  1196.  
  1197. 報告を寄せて下さった方には何故そうなるのかをきちんと説明したのですが、い
  1198.  
  1199. ちいち「(.not.$AA).and.$FF」または「$AA.xor.$FF」と書いてもらうのも面倒
  1200.  
  1201. だろうと思ったので、専用の演算子を作ってしまいました。
  1202.  
  1203.  
  1204.  HAS060.X のマニュアルからそのまま引用してしまいますが、.notb. と
  1205.  
  1206. .notw. の定義は次のようになっています。
  1207.  
  1208.     .NOTB.<式> ::= (.NOT.<式>).AND.$FF
  1209.     .NOTW.<式> ::= (.NOT.<式>).AND.$FFFF
  1210.  
  1211. つまり、
  1212.  
  1213.     .notb.$55 = $000000AA
  1214.     .notb.$AA = $00000055
  1215.     .notw.$5555 = $0000AAAA
  1216.     .notw.$AAAA = $00005555
  1217.  
  1218. という具合です。先ほどのソースも、
  1219.  
  1220.       ┌────────────────────────────
  1221.       │    .dc.b    .notb.$55
  1222.       │    .dc.b    .notb.$AA
  1223.  
  1224. と書けば、
  1225.  
  1226.       ┌────────────────────────────
  1227.       │<test.s>
  1228.       │    1 00000000 AA                   .dc.b    .notb.$55
  1229.       │    2 00000001 55                   .dc.b    .notb.$AA
  1230.  
  1231. となって、これで問題解決です。
  1232.  
  1233.  
  1234. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  1235.  
  1236.  思いついたところをいろいろ挙げてみましたが、いかがでしたでたか?
  1237.  
  1238.  
  1239.  「こんな使い方があったのか!」という発見がありましたか?
  1240.  
  1241.  
  1242.  
  1243. (EOF)
  1244.  
  1245.